From e83d6b9432af603200f065b499b8e4b78e92842d Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 17 Apr 2013 13:52:34 +0100 Subject: [PATCH] arm: vgic: fix race in vgic_vcpu_inject_irq The initial check for a still pending interrupt (!list_empty(&n->inflight)) needs to be covered by the vgic lock to avoid trying to insert the IRQ into the inflight list simultaneously on 2 pCPUS. Expand the area covered by the lock appropriately. Also consolidate the unlocks on the exit path into one location. Signed-off-by: Ian Campbell Acked-by: Stefano Stabellini --- xen/arch/arm/vgic.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index d9ceaaaec0..4d8da0242e 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -584,9 +584,14 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual) struct pending_irq *iter, *n = irq_to_pending(v, irq); unsigned long flags; - /* irq still pending */ + spin_lock_irqsave(&v->arch.vgic.lock, flags); + + /* irq already pending */ if (!list_empty(&n->inflight)) + { + spin_unlock_irqrestore(&v->arch.vgic.lock, flags); return; + } priority = byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, byte); @@ -601,17 +606,16 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual) if ( rank->ienable & (1 << (irq % 32)) ) gic_set_guest_irq(v, irq, GICH_LR_PENDING, priority); - spin_lock_irqsave(&v->arch.vgic.lock, flags); list_for_each_entry ( iter, &v->arch.vgic.inflight_irqs, inflight ) { if ( iter->priority > priority ) { list_add_tail(&n->inflight, &iter->inflight); - spin_unlock_irqrestore(&v->arch.vgic.lock, flags); - return; + goto out; } } list_add_tail(&n->inflight, &v->arch.vgic.inflight_irqs); +out: spin_unlock_irqrestore(&v->arch.vgic.lock, flags); /* we have a new higher priority irq, inject it into the guest */ } -- 2.30.2